/**
 * Copyright (c) 2009-2012 XTEAM
 * All rights reserved.
 */
/**
 * File：FileService.java
 * History:
 *         2012-5-17: Initially created, Chrise.
 */
package com.xteam.ecsystem.service.admin;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.apache.commons.fileupload.FileItem;
import org.springframework.stereotype.Service;

import com.tangkf.utils.CommonUtils;
import com.xteam.ecsystem.base.DirectoryFilter;
import com.xteam.ecsystem.base.FileFilter;
import com.xteam.ecsystem.base.FileObject;
import com.xteam.ecsystem.base.FileSorter;
import com.xteam.ecsystem.utils.AppConfig;
import com.xteam.ecsystem.utils.PageCenterStation;

/**
 * 文件管理服务层。
 * @author Chrise
 */
@Service
public class FileService {
	
	private static String TYPE_OF_DIR = "folder";
	private static double BYTES_OF_KB = 1024.0;
	private static String FORMAT_OF_SIZE = "%.0f KB";
	private static String ROOT_PATH = "/";
	private static String ROOT_PARENT = "-";
	private static String PATH_LEFT = "/";
	private static String PATH_RIGHT = "\\";
	
	/**
	 * 获取目录。
	 * @author Chrise 2012-5-21
	 * @param forRes
	 * @return
	 */
	public List<FileObject> getDirectorys(boolean forRes) {
		String rootPath = this.getRootPath(forRes);
		
		File rootFile = new File(rootPath);
		if (rootFile.exists() && rootFile.isDirectory()) {
			List<FileObject> list = new ArrayList<FileObject>();
			list.add(new FileObject(ROOT_PATH, this.getRootName(forRes), ROOT_PARENT));
			
			this.searchChildDirectory(rootFile, ROOT_PATH, rootPath.length(), list);
			
			return list;
		}
		
		return null;
	}
	
	/**
	 * 获取指定路径下的文件。
	 * @author Chrise 2012-5-23
	 * @param forRes
	 * @param parentPath
	 * @param pageIndex
	 * @param pageSize
	 * @return
	 */
	public PageCenterStation<FileObject> getFilesByPath(boolean forRes, String parentPath, int pageIndex, int pageSize) {
		String rootPath = this.getRootPath(forRes);
		
		File parent = new File(rootPath + parentPath);
		if (parent.exists() && parent.isDirectory()) {
			File[] dc = parent.listFiles(new DirectoryFilter());
			File[] fc = parent.listFiles(new FileFilter());
			Arrays.sort(dc, new FileSorter());
			Arrays.sort(fc, new FileSorter());
			List<File> children = new ArrayList<File>(Arrays.asList(dc));
			children.addAll(Arrays.asList(fc));
			
			List<FileObject> list = new ArrayList<FileObject>();
			for (int i = pageIndex * pageSize; i < children.size() && list.size() < pageSize; i ++) {
				File child = children.get(i);
				
				String path = child.getPath().substring(rootPath.length());
				path = path.replace(PATH_RIGHT, PATH_LEFT);
				String name = child.getName();
				FileObject fo = new FileObject(path, name, parentPath);
				
				if (child.isDirectory()) {
					fo.setType(TYPE_OF_DIR);
				} else {
					int index = name.lastIndexOf(".");
					if (index != -1) {
						fo.setType(name.substring(index + 1));
					}
				}
				
				double size = Math.ceil(child.length() / BYTES_OF_KB);
				if (size == 0) size ++;
				fo.setSize(String.format(FORMAT_OF_SIZE, size));
				
				Date last = new Date(child.lastModified());
				fo.setLast(CommonUtils.getStDateTime(last));
				
				list.add(fo);
			}
			
			return new PageCenterStation<FileObject>(children.size(), list);
		}
		
		return null;
	}
	
	/**
	 * 编辑文件名。
	 * @author Chrise 2012-5-24
	 * @param forRes
	 * @param isCreate
	 * @param name
	 * @param orgin
	 * @param parent
	 * @return
	 * @throws IOException
	 */
	public boolean editFileName(boolean forRes, boolean isCreate, String name, String orgin, String parent) throws IOException {
		String rootPath = this.getRootPath(forRes);
		if (ROOT_PATH.equals(parent)) parent = "";
		
		File des = new File(rootPath + parent + PATH_LEFT + name);
		if (isCreate) {
			if (des.exists()) {
				return false;
			}
			if (!des.mkdir()) {
				throw new IOException("Unknown error.");
			}
		} else {
			File src = new File(rootPath + parent + PATH_LEFT + orgin);
			if (!src.exists()) {
				throw new IOException("The file does not exist.");
			}
			if (des.exists()) {
				if (src.getName().equals(des.getName())) {
					return true;
				} else {
					return false;
				}
			}
			if (!src.renameTo(des)) {
				throw new IOException("Unknown error.");
			}
		}
		
		return true;
	}
	
	/**
	 * 删除指定路径的文件。
	 * @author Chrise 2012-5-25
	 * @param forRes
	 * @param paths
	 * @return
	 */
	public String delFilesByPaths(boolean forRes, List<String> paths) {
		String rootPath = this.getRootPath(forRes);
		
		for (String path : paths) {
			File des = new File(rootPath + path);
			if (!this.deleteFile(des)) {
				return des.getName();
			}
		}
		
		return null;
	}
	
	/**
	 * 上传文件。
	 * @author Chrise 2012-5-29
	 * @param forRes
	 * @param parent
	 * @param list
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public void uploadFiles(boolean forRes, String parent, List list) throws Exception {
		String rootPath = this.getRootPath(forRes);
		if (ROOT_PATH.equals(parent)) parent = "";
		
		for (Object object : list) {
			if (object instanceof FileItem) {
				FileItem item = (FileItem)object;
				if (item.isFormField()) continue;
				
				String path = rootPath + parent + PATH_LEFT + item.getName();
				item.write(new File(path));
			}
		}
	}
	
	/**
	 * 编辑文件内容。
	 * @author Chrise 2012-5-30
	 * @param forRes
	 * @param isCreate
	 * @param name
	 * @param parent
	 * @param content
	 * @return
	 * @throws IOException
	 */
	public boolean editContent(boolean forRes, boolean isCreate, String name, String parent, String content) 
		throws IOException {
		String rootPath = this.getRootPath(forRes);
		if (ROOT_PATH.equals(parent)) parent = "";
		
		String path = rootPath + parent + PATH_LEFT + name;
		
		File des = new File(path);
		if (isCreate && des.exists()) return false;
		
		byte[] data = content.getBytes("UTF-8");
		
		FileOutputStream fos = new FileOutputStream(des);
		fos.write(data);
		fos.flush();
		fos.close();
		
		return true;
	}
	
	/**
	 * 获取文件内容。
	 * @author Chrise 2012-5-30
	 * @param forRes
	 * @param name
	 * @param parent
	 * @return
	 * @throws IOException
	 */
	public String getContent(boolean forRes, String name, String parent) throws IOException {
		String rootPath = this.getRootPath(forRes);
		if (ROOT_PATH.equals(parent)) parent = "";
		
		String path = rootPath + parent + PATH_LEFT + name;
		
		File des = new File(path);
		if (!des.exists()) return null;
		
		FileInputStream fis = new FileInputStream(des);
		int size = fis.available();
		if (size <= 0) return "";
		
		byte[] data = new byte[size];
		fis.read(data);
		fis.close();
		
		return new String(data, "UTF-8");
	}
	
	/**
	 * 获取模板。
	 * @author Chrise 2012-6-11
	 * @return
	 */
	public List<FileObject> getTemplates() {
		String rootPath = this.getRootPath(false);
		
		File rootFile = new File(rootPath);
		if (rootFile.exists() && rootFile.isDirectory()) {
			List<FileObject> list = new ArrayList<FileObject>();
			
			if (this.loadTemplates(rootFile, ROOT_PATH, rootPath.length(), list)) {
				list.add(new FileObject(ROOT_PATH, this.getRootName(false), ROOT_PARENT));
			}
			
			return list;
		}
		
		return null;
	}
	
	/**
	 * 获取模板方案。
	 * @author Chrise 2012-6-12
	 * @return
	 */
	public List<FileObject> getTemplateNames() {
		String rootPath = this.getRootPath(false);
		
		File rootFile = new File(rootPath);
		if (rootFile.exists() && rootFile.isDirectory()) {
			List<FileObject> list = new ArrayList<FileObject>();
			
			File[] children = rootFile.listFiles(new DirectoryFilter());
			if (children.length <= 0) return list;
			
			Arrays.sort(children, new FileSorter());
			for (File child : children) {
				list.add(new FileObject("", child.getName(), ""));
			}
			
			return list;
		}
		
		return null;
	}
	
	/**
	 * 获取根名称。
	 * @author Chrise 2012-5-21
	 * @param forRes
	 * @return
	 */
	private String getRootName(boolean forRes) {
		if (forRes) {
			return AppConfig.getResRootName();
		}
		
		return AppConfig.getTplRootName();
	}
	
	/**
	 * 获取根路径。
	 * @author Chrise 2012-5-21
	 * @param forRes
	 * @return
	 */
	private String getRootPath(boolean forRes) {
		if (forRes) {
			return AppConfig.getResRootPath();
		}
		
		return AppConfig.getTplRootPath();
	}
	
	/**
	 * 搜索子目录。
	 * @author Chrise 2012-5-21
	 * @param parentFile
	 * @param parentPath
	 * @param rootLength
	 * @param list
	 */
	private void searchChildDirectory(File parentFile, String parentPath, int rootLength, List<FileObject> list) {
		File[] children = parentFile.listFiles(new DirectoryFilter());
		Arrays.sort(children, new FileSorter());
		
		for (int i = 0; i < children.length; i ++) {
			File child = children[i];
			
			String path = child.getPath().substring(rootLength);
			path = path.replace(PATH_RIGHT, PATH_LEFT);
			list.add(new FileObject(path, child.getName(), parentPath));
			
			this.searchChildDirectory(child, path, rootLength, list);
		}
	}
	
	/**
	 * 删除文件。
	 * @author Chrise 2012-5-25
	 * @param des
	 * @return
	 */
	private boolean deleteFile(File des) {
		if (!des.exists()) {
			return true;
		}
		
		if (des.isDirectory()) {
			File[] children = des.listFiles();
			for (File child : children) {
				if (!this.deleteFile(child)) {
					return false;
				}
			}
		}
		
		return des.delete();
	}
	
	/**
	 * 加载模板。
	 * @author Chrise 2012-6-13
	 * @param parent
	 * @param directory
	 * @param length
	 * @param list
	 * @return
	 */
	private boolean loadTemplates(File parent, String directory, int length, List<FileObject> list) {
		File[] dcs = parent.listFiles(new DirectoryFilter());
		File[] fcs = parent.listFiles(new FileFilter());
		if (dcs.length <= 0 && fcs.length <= 0) return false;
		
		boolean loaded = false;
		Arrays.sort(dcs, new FileSorter());
		for (File dc : dcs) {
			String path = dc.getPath().substring(length);
			path = path.replace(PATH_RIGHT, PATH_LEFT);
			if (this.loadTemplates(dc, path, length, list)) {
				loaded = true;
				list.add(new FileObject(path, dc.getName(), directory));
			}
		}
		
		if (!loaded && fcs.length <= 0) return false;
		
		Arrays.sort(fcs, new FileSorter());
		for (File fc : fcs) {
			String path = fc.getPath().substring(length);
			path = path.replace(PATH_RIGHT, PATH_LEFT);
			list.add(new FileObject(path, fc.getName(), directory));
		}
		
		return true;
	}
}
